package com.credithc.eagleeye.api.service.impl;
import com.credithc.eagleeye.api.factory.ESFactory;
import com.credithc.eagleeye.api.job.AlertJobManager;
import com.credithc.eagleeye.api.protocol.AlertLogSearchRes;
import com.credithc.eagleeye.api.service.SettingService;
import com.credithc.eagleeye.api.vo.AlertLogSearchConditionVo;
import com.credithc.eagleeye.api.vo.AlertLogVo;
import com.credithc.eagleeye.api.vo.AlertRuleVo;
import com.credithc.eagleeye.api.vo.PlatformVo;
import com.credithc.eagleeye.api.vo.SettingVo;
import com.credithc.eagleeye.api.vo.UserVo;
import com.credithc.framework.es.util.ElasticSearchUtil;
import com.credithc.framework.utils.date.DateTools;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.sort.SortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
 * 描 述: <br/>
 * 作 者: zhangjin<br/>
 * 创 建：2018年10月16日<br/>
 * 版 本：v1.0.0<br>
 * <p>
 * 历 史: (版本) 作者 时间 注释 <br/>
 */
@SuppressWarnings("Duplicates")
@Service
@Slf4j
public class SettingServiceImpl implements SettingService {
    private static final String SETTING_INDEX = ".eagleeye-setting";
    private static final String SETTING_TYPE = "setting";
    private static final String SETTING_TYPE_ID = "setting";
    private static final String PLATFORM_TYPE = "platform";
    private static final String USER_TYPE = "user";
    private static final String ALERT_RULE_TYPE = "alert";
    private static final String ALERT_LOG_ES_INDEX = ".eagle-alert-log";
    private static final String ALERT_LOG_ES_TYPE = "log";

    @Autowired
    private AlertJobManager alertJobManager;

    @Override
    @Cacheable(value="platformAllCache")
    public List<PlatformVo> loadAllPlatform() {
        ElasticSearchUtil elasticSearchUtil = ESFactory.getInstance();
        BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
        List<PlatformVo> platformVoList = elasticSearchUtil.search(PlatformVo.class, SETTING_INDEX, PLATFORM_TYPE, boolQueryBuilder,null,1024);
        return platformVoList;
    }
    @Override
    @Cacheable(value="platformCache",key="#platformName")
    public PlatformVo loadPlatform(String platformName) {
        PlatformVo platformVo = null;
        ElasticSearchUtil elasticSearchUtil = ESFactory.getInstance();
        BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
        boolQueryBuilder.must(QueryBuilders.matchPhraseQuery("_id", platformName));
        List<PlatformVo> platformVoList = elasticSearchUtil.search(PlatformVo.class, SETTING_INDEX, PLATFORM_TYPE, boolQueryBuilder);
        if (platformVoList != null && platformVoList.size() > 0) {
            platformVo = platformVoList.get(0);
        }
        return platformVo;
    }

    @Override
    @Caching(evict = {
            @CacheEvict(value="platformCache",key="#platformVo.name"),
            @CacheEvict(value="platformAllCache",allEntries = true)
    })
    public void savePlatform(PlatformVo platformVo) {
        if(platformVo!=null&&StringUtils.isNotBlank(platformVo.getName())) {
            ElasticSearchUtil elasticSearchUtil = ESFactory.getInstance();
            elasticSearchUtil.insertOrUpdateDocument(SETTING_INDEX, PLATFORM_TYPE, platformVo.getName(),platformVo);
        }
    }
    @Override
    @Caching(evict = {
            @CacheEvict(value="platformCache",key="#platformVo.name"),
            @CacheEvict(value="platformAllCache",allEntries = true)
    })
    public void deletePlatform(PlatformVo platformVo) {
        if(platformVo!=null&&StringUtils.isNotBlank(platformVo.getName())) {
            ElasticSearchUtil elasticSearchUtil = ESFactory.getInstance();
            elasticSearchUtil.deleteDocument(SETTING_INDEX,PLATFORM_TYPE,platformVo.getName());
        }
    }

    @Override
    @Cacheable(value="settingCache")
    public SettingVo loadSetting() {
        SettingVo settingVo = new SettingVo();
        ElasticSearchUtil elasticSearchUtil = ESFactory.getInstance();
        BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
        boolQueryBuilder.must(QueryBuilders.matchPhraseQuery("_id", SETTING_TYPE_ID));
        List<SettingVo> settingVoList = elasticSearchUtil.search(SettingVo.class, SETTING_INDEX, SETTING_TYPE, boolQueryBuilder);
        if (settingVoList != null && settingVoList.size() > 0) {
            settingVo = settingVoList.get(0);
        }
        return settingVo;
    }

    @Override
    @CacheEvict(value = "settingCache",allEntries = true)
    public void saveSetting(SettingVo settingVo) {
        if(settingVo!=null) {
            ElasticSearchUtil elasticSearchUtil = ESFactory.getInstance();
            boolean b = elasticSearchUtil.insertOrUpdateDocument(SETTING_INDEX, SETTING_TYPE, SETTING_TYPE_ID, settingVo);
        }
    }

    @Override
    @Cacheable(value="userAllCache")
    public List<UserVo> loadAllUser() {
        ElasticSearchUtil elasticSearchUtil = ESFactory.getInstance();
        BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
        List<UserVo> userVoList = elasticSearchUtil.search(UserVo.class, SETTING_INDEX, USER_TYPE, boolQueryBuilder,null,1024);
        return userVoList;
    }
    @Override
    @Cacheable(value="userCache",key="#userName")
    public UserVo loadUser(String userName) {
        UserVo userVo = null;
        ElasticSearchUtil elasticSearchUtil = ESFactory.getInstance();
        BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
        boolQueryBuilder.must(QueryBuilders.matchPhraseQuery("_id", userName));
        List<UserVo> userVoList = elasticSearchUtil.search(UserVo.class, SETTING_INDEX, USER_TYPE, boolQueryBuilder);
        if(userVoList!=null){
            userVo= userVoList.get(0);
        }
        return userVo;
    }
    @Override
    @Caching(evict = {
            @CacheEvict(value="userCache",key="#userVo.userName"),
            @CacheEvict(value="userAllCache",allEntries = true)
    })
    public void saveUser(UserVo userVo) {
        if(userVo!=null) {
            ElasticSearchUtil elasticSearchUtil = ESFactory.getInstance();
            if (StringUtils.equals(userVo.getUserName(), "admin")) {
                ArrayList<String> platformList = new ArrayList<>();
                platformList.add("all");
                userVo.setPlatformList(platformList);
            }
            elasticSearchUtil.insertOrUpdateDocument(SETTING_INDEX, USER_TYPE, userVo.getUserName(),userVo);
        }
    }

    @Override
    @Caching(evict = {
            @CacheEvict(value="userCache",key="#userVo.userName"),
            @CacheEvict(value="userAllCache",allEntries = true)
    })
    public void deleteUser(UserVo userVo) {
        if(userVo!=null&&StringUtils.isNotBlank(userVo.getUserName())) {
            ElasticSearchUtil elasticSearchUtil = ESFactory.getInstance();
            elasticSearchUtil.deleteDocument(SETTING_INDEX,USER_TYPE,userVo.getUserName());
        }
    }
    @Override
    public List<AlertRuleVo> loadAllAlertRule() {
        ElasticSearchUtil elasticSearchUtil = ESFactory.getInstance();
        BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
        List<SortBuilder> sortBuilderList = new ArrayList<>();
        SortBuilder sort = SortBuilders.fieldSort("ruleId").order(SortOrder.ASC);
        sortBuilderList.add(sort);
        List<AlertRuleVo> alertRuleVoList = elasticSearchUtil.search(AlertRuleVo.class, SETTING_INDEX, ALERT_RULE_TYPE, boolQueryBuilder,sortBuilderList,1024);
        return alertRuleVoList;
    }
    @Override
    public AlertRuleVo loadAlertRule(String ruleId) {
        AlertRuleVo alertRuleVo = null;
        ElasticSearchUtil elasticSearchUtil = ESFactory.getInstance();
        BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
        boolQueryBuilder.must(QueryBuilders.matchPhraseQuery("_id", ruleId));
        List<AlertRuleVo> alertRuleVoList = elasticSearchUtil.search(AlertRuleVo.class, SETTING_INDEX, ALERT_RULE_TYPE, boolQueryBuilder);
        if(alertRuleVoList!=null){
            alertRuleVo= alertRuleVoList.get(0);
        }
        return alertRuleVo;
    }
    @Override
    public void saveAlertRule(AlertRuleVo alertRuleVo) {
        if(alertRuleVo!=null&&StringUtils.isNotBlank(alertRuleVo.getRuleId())) {
            ElasticSearchUtil elasticSearchUtil = ESFactory.getInstance();
            elasticSearchUtil.insertOrUpdateDocument(SETTING_INDEX, ALERT_RULE_TYPE, alertRuleVo.getRuleId(),alertRuleVo);
            alertJobManager.addOrUpdate(alertRuleVo);
        }
    }
    @Override
    public void deleteAlertRule(AlertRuleVo alertRuleVo) {
        if(alertRuleVo!=null&&StringUtils.isNotBlank(alertRuleVo.getRuleId())) {
            ElasticSearchUtil elasticSearchUtil = ESFactory.getInstance();
            elasticSearchUtil.deleteDocument(SETTING_INDEX,ALERT_RULE_TYPE,alertRuleVo.getRuleId());
            alertJobManager.cancel(alertRuleVo.getRuleId());
        }
    }

    @Override
    public AlertLogSearchRes searchAlertLog(AlertLogSearchConditionVo conditionVo) {
        ElasticSearchUtil elasticSearchUtil = ESFactory.getInstance();
        BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
        List<SortBuilder> sortBuilderList = new ArrayList<>();
        SortBuilder sort = SortBuilders.fieldSort("alertTime").order(SortOrder.DESC);
        sortBuilderList.add(sort);

        long toTime = 0;
        long formTime = 0;
        int pageSize = conditionVo.getPageSize();
        int from = pageSize * (conditionVo.getPageNum() - 1);

        if (StringUtils.isNotBlank(conditionVo.getFromDate())) {
            formTime = DateTools.Date19ToDate(conditionVo.getFromDate()).getTime();
        }
        if (StringUtils.isNotBlank(conditionVo.getToDate())) {
            toTime = DateTools.Date19ToDate(conditionVo.getToDate()).getTime();
        }

        //2.x里不能用过滤器了
        if (formTime != 0) {
            boolQueryBuilder.must(QueryBuilders.rangeQuery("alertTime").from(formTime));
        }
        if (toTime != 0) {
            boolQueryBuilder.must(QueryBuilders.rangeQuery("alertTime").to(toTime));
        }
        if (StringUtils.isNotBlank(conditionVo.getRuleId())) {
            boolQueryBuilder.must(QueryBuilders.matchPhraseQuery("ruleId", conditionVo.getRuleId()));
        }
        if (StringUtils.isNotBlank(conditionVo.getLevel())) {
            boolQueryBuilder.must(QueryBuilders.matchPhraseQuery("level", conditionVo.getLevel()));
        }
        if (StringUtils.isNotBlank(conditionVo.getPlatformName())) {
            boolQueryBuilder.must(QueryBuilders.matchPhraseQuery("platformName", conditionVo.getPlatformName()));
        }
        if (StringUtils.isNotBlank(conditionVo.getEnv())) {
            boolQueryBuilder.must(QueryBuilders.matchPhraseQuery("env", StringUtils.trimToEmpty(conditionVo.getEnv())));
        }


        List<AlertLogVo> alertLogVoList = elasticSearchUtil.search(AlertLogVo.class, ALERT_LOG_ES_INDEX, ALERT_LOG_ES_TYPE, boolQueryBuilder,sortBuilderList, from, pageSize);

        for(AlertLogVo vo : alertLogVoList) {
            String alertTime = vo.getAlertTime();
            if(alertTime.indexOf("T")>-1) {
                vo.setAlertTime(alertTime.replace("T", " ").substring(0, 23));
            }else if(StringUtils.isNumeric(alertTime)){
                vo.setAlertTime(DateTools.FormatDate19(new Date(Long.parseLong(alertTime))));
            }
        }

        long count = elasticSearchUtil.count(ALERT_LOG_ES_INDEX, ALERT_LOG_ES_TYPE, boolQueryBuilder);

        AlertLogSearchRes alertLogSearchRes = new AlertLogSearchRes();
        alertLogSearchRes.setAlertLogVoList(alertLogVoList);
        alertLogSearchRes.setTotalCount(count);
        alertLogSearchRes.setPageNum(conditionVo.getPageNum());
        alertLogSearchRes.setPageSize(conditionVo.getPageSize());
        return alertLogSearchRes;
    }
}
